package elements

import (
	"bytes"
	"github.com/pkg/errors"
	"strconv"
	"yizhuoyan/go-study/pdfgo/characterset"
	"yizhuoyan/go-study/pdfgo/handyio"
)

var startxrefKeywordBytes = []byte("startxref")
var eofKeywordBytes = []byte("%%EOF")

type StartXrefElement struct {
	XrefStartIndex int64 `validate:"required" #:""`
}

func (this *StartXrefElement) Write(w handyio.PdfRawWriter) error {
	w.WriteBytes(startxrefKeywordBytes)
	w.WriteEndOfLine()
	w.WriteInt64(this.XrefStartIndex)
	w.WriteEndOfLine()
	w.WriteBytes(eofKeywordBytes)
	w.WriteEndOfLine()
	return nil
}

func (this *StartXrefElement) Read(r handyio.PdfRawReader) error {
	if err := r.IndexMoveTo(r.IndexEnd()); err != nil {
		return err
	}
	var backwardReader = &pdfRawBackwardReader{
		PdfRawReader: r,
		index:        r.IndexCurrent(),
	}
	backwardReader.PreviousSkipWhiteSpace()
	if !backwardReader.PreviousBytesEquals(eofKeywordBytes) {
		return errors.Errorf("无EOF")
	}
	backwardReader.PreviousSkipWhiteSpace()
	offsetBytes := backwardReader.PreviousBytesUntilWhiteSpace()
	offsetInt, err := strconv.ParseInt(string(offsetBytes), 10, 64)
	if err != nil {
		return errors.New("无offset")
	}
	this.XrefStartIndex = offsetInt
	backwardReader.PreviousSkipWhiteSpace()
	if !backwardReader.PreviousBytesEquals(startxrefKeywordBytes) {
		return errors.Errorf("无startxref")
	}
	return nil
}

type pdfRawBackwardReader struct {
	handyio.PdfRawReader
	index int64
}

func (this *pdfRawBackwardReader) previousByte() (byte, error) {
	startAt := this.IndexCurrent()
	if err := this.IndexMoveTo(startAt - 1); err != nil {
		return 0, err
	}
	nextByte, err := this.NextByte()
	if err != nil {
		return 0, err
	}
	//确认回退1位
	if err = this.IndexMoveTo(startAt - 1); err != nil {
		return 0, err
	}
	return nextByte, nil
}
func (this *pdfRawBackwardReader) PreviousSkipWhiteSpace() {
	for true {
		previousByte, err := this.previousByte()
		if err != nil {
			break
		}
		if !characterset.IsWhiteSpaceChar(previousByte) {
			_ = this.IndexMoveTo(this.IndexCurrent() + 1)
			break
		}
	}
}
func (this *pdfRawBackwardReader) PreviousBytesEquals(bs []byte) bool {
	startAt := this.IndexCurrent()
	for i := len(bs) - 1; i >= 0; i-- {
		previousByte, err := this.previousByte()
		if err != nil {
			break
		}
		if bs[i] != previousByte {
			_ = this.IndexMoveTo(startAt)
			return false
		}
	}
	return true
}
func (this *pdfRawBackwardReader) PreviousBytesUntilWhiteSpace() []byte {
	var buf = new(bytes.Buffer)
	for true {
		previousByte, err := this.previousByte()
		if err != nil {
			break
		}
		if characterset.IsWhiteSpaceChar(previousByte) {
			_ = this.IndexMoveTo(this.IndexCurrent() + 1)
			break
		} else {
			buf.WriteByte(previousByte)
		}
	}
	//倒序
	bs := buf.Bytes()
	for i, j := 0, len(bs)-1; i < j; i, j = i+1, j-1 {
		bs[i], bs[j] = bs[j], bs[i]
	}
	return bs
}
